package main

import (
	"fmt"
	"os"
	"time"

	"github.com/urfave/cli"
)

func init() {
	//cli.AppHelpTemplate += "\nCUSTOMIZED: you bet ur muffins\n"
	//cli.CommandHelpTemplate += "\nYMMV\n"
	//cli.SubcommandHelpTemplate += "\nor something\n"

	//cli.HelpFlag = cli.BoolFlag{Name: "halp"}
	//cli.BashCompletionFlag = cli.BoolFlag{Name: "compgen", Hidden: true}
	cli.VersionFlag = cli.BoolFlag{Name: "version, V"}

	//cli.HelpPrinter = func(w io.Writer, templ string, data interface{}) {
	//	fmt.Fprintf(w, "best of luck to you\n")
	//}
	//cli.VersionPrinter = func(c *cli.Context) {
	//	fmt.Fprintf(c.App.Writer, "version=%s\n", c.App.Version)
	//}
	//cli.OsExiter = func(c int) {
	//	fmt.Fprintf(cli.ErrWriter, "refusing to exit %d\n", c)
	//}
	//cli.ErrWriter = ioutil.Discard
	//cli.FlagStringer = func(fl cli.Flag) string {
	//	return fmt.Sprintf("\t\t%s", fl.GetName())
	//}
}

type hexWriter struct{}

func (w *hexWriter) Write(p []byte) (int, error) {
	for _, b := range p {
		fmt.Printf("%x", b)
	}
	fmt.Printf("\n")

	return len(p), nil
}

type genericType struct {
	s string
}

func (g *genericType) Set(value string) error {
	g.s = value
	return nil
}

func (g *genericType) String() string {
	return g.s
}

func main() {
	app := cli.NewApp()
	app.Name = "contrive"
	app.Version = "19.99.0"
	app.Compiled = time.Now()
	app.Authors = []cli.Author{
		cli.Author{
			Name:  "Example Human",
			Email: "human@example.com",
		},
	}
	app.Copyright = "(c) 1999 Serious Enterprise"
	app.HelpName = "contrive"
	app.Usage = "demonstrate available API"
	app.UsageText = "contrive - demonstrating the available API"
	app.ArgsUsage = "[args and such]"
	app.Commands = []cli.Command{
		cli.Command{
			Name:        "doo",
			Aliases:     []string{"do"},
			Category:    "motion",
			Usage:       "do the doo",
			UsageText:   "doo - does the dooing",
			Description: "no really, there is a lot of dooing to be done",
			ArgsUsage:   "[arg usage]",
			Flags: []cli.Flag{
				cli.BoolFlag{Name: "forever, f"},
			},
			Subcommands: cli.Commands{
				cli.Command{
					Name:   "wop",
					Action: wopAction,
				},
			},
			//SkipFlagParsing: false,
			//HideHelp:        false,
			//Hidden:          false,
			//HelpName:        "doo!",
			BashComplete: func(c *cli.Context) {
				fmt.Fprintf(c.App.Writer, "--doo bashcomplete,better\n")
			},
			Before: func(c *cli.Context) error {
				fmt.Fprintf(c.App.Writer, "before doo,brace for impact\n")
				return nil
			},
			After: func(c *cli.Context) error {
				fmt.Fprintf(c.App.Writer, "after doo,did we lose anyone?\n")
				return nil
			},
			Action: func(c *cli.Context) error {
				c.Command.FullName()
				c.Command.HasName("wop")
				c.Command.Names()
				c.Command.VisibleFlags()
				fmt.Fprintf(c.App.Writer, "action,dodododododoodododddooooododododooo\n")
				if c.Bool("forever") {
					c.Command.Run(c)
				}
				return nil
			},
			OnUsageError: func(c *cli.Context, err error, isSubcommand bool) error {
				fmt.Fprintf(c.App.Writer, "usage error of doo,for shame\n")
				return err
			},
		},
	}
	app.Flags = []cli.Flag{
		cli.BoolFlag{Name: "fancy"},
		cli.BoolTFlag{Name: "fancier"},
		cli.DurationFlag{Name: "howlong, H", Value: time.Second * 3},
		cli.Float64Flag{Name: "howmuch"},
		cli.GenericFlag{Name: "wat", Value: &genericType{}},
		cli.Int64Flag{Name: "longdistance"},
		cli.Int64SliceFlag{Name: "intervals"},
		cli.IntFlag{Name: "distance"},
		cli.IntSliceFlag{Name: "times"},
		cli.StringFlag{Name: "dance-move, d"},
		cli.StringSliceFlag{Name: "names, N"},
		cli.UintFlag{Name: "age"},
		cli.Uint64Flag{Name: "bigage"},
	}
	app.EnableBashCompletion = true
	app.UseShortOptionHandling = true
	app.HideHelp = false
	app.HideVersion = false
	app.BashComplete = func(c *cli.Context) {
		fmt.Fprintf(c.App.Writer, "lipstick\nkiss\nme\nlipstick\nringo\n")
	}
	//app.Before = func(c *cli.Context) error {
	//	fmt.Fprintf(c.App.Writer, "app.before,HEEEERE GOES\n")
	//	return nil
	//}
	//app.After = func(c *cli.Context) error {
	//	fmt.Fprintf(c.App.Writer, "app.after,Phew!\n")
	//	return nil
	//}
	app.CommandNotFound = func(c *cli.Context, command string) {
		fmt.Fprintf(c.App.Writer, "command not found:%q\n", command)
	}
	app.OnUsageError = func(c *cli.Context, err error, isSubcommand bool) error {
		if isSubcommand {
			return err
		}

		fmt.Fprintf(c.App.Writer, "app, usage error,WRONG: %#v\n", err)
		return nil
	}
	app.Action = func(c *cli.Context) error {
		//cli.DefaultAppComplete(c)
		//cli.HandleExitCoder(errors.New("not an exit coder, though"))
		cli.ShowAppHelp(c)
		//cli.ShowCommandCompletions(c, "nope")
		//cli.ShowCommandHelp(c, "also-nope")
		//cli.ShowCompletions(c)
		//cli.ShowSubcommandHelp(c)
		//cli.ShowVersion(c)

		//categories := c.App.Categories()
		//categories.AddCommand("sounds", cli.Command{
		//	Name: "bloop",
		//})
		//
		//for _, category := range c.App.Categories() {
		//	fmt.Fprintf(c.App.Writer, "%s\n", category.Name)
		//	fmt.Fprintf(c.App.Writer, "%#v\n", category.Commands)
		//	fmt.Fprintf(c.App.Writer, "%#v\n", category.VisibleCommands())
		//}
		//
		//fmt.Printf("%#v\n", c.App.Command("doo"))
		//if c.Bool("infinite") {
		//	c.App.Run([]string{"app", "doo", "wop"})
		//}
		//
		//if c.Bool("forever") {
		//	c.App.RunAsSubcommand(c)
		//}
		c.App.Setup()
		//fmt.Printf("%#v\n", c.App.VisibleCategories())
		//fmt.Printf("%#v\n", c.App.VisibleCommands())
		//fmt.Printf("%#v\n", c.App.VisibleFlags())
		//
		//fmt.Printf("%#v\n", c.Args().First())
		//if len(c.Args()) > 0 {
		//	fmt.Printf("%#v\n", c.Args()[1])
		//}
		//fmt.Printf("%#v\n", c.Args().Present())
		//fmt.Printf("%#v\n", c.Args().Tail())
		//
		//set := flag.NewFlagSet("contrive", 0)
		//nc := cli.NewContext(c.App, set, c)
		//
		//fmt.Printf("%#v\n", nc.Args())
		//fmt.Printf("%#v\n", nc.Bool("nope"))
		//fmt.Printf("%#v\n", nc.BoolT("nerp"))
		//fmt.Printf("%#v\n", nc.Duration("howlong"))
		//fmt.Printf("%#v\n", nc.Float64("hay"))
		//fmt.Printf("%#v\n", nc.Generic("bloop"))
		//fmt.Printf("%#v\n", nc.Int64("bonk"))
		//fmt.Printf("%#v\n", nc.Int64Slice("burnks"))
		//fmt.Printf("%#v\n", nc.Int("bips"))
		//fmt.Printf("%#v\n", nc.IntSlice("blups"))
		//fmt.Printf("%#v\n", nc.String("snurt"))
		//fmt.Printf("%#v\n", nc.StringSlice("snurkles"))
		//fmt.Printf("%#v\n", nc.Uint("flub"))
		//fmt.Printf("%#v\n", nc.Uint64("florb"))
		//fmt.Printf("%#v\n", nc.GlobalBool("global-nope"))
		//fmt.Printf("%#v\n", nc.GlobalBoolT("global-nerp"))
		//fmt.Printf("%#v\n", nc.GlobalDuration("global-howlong"))
		//fmt.Printf("%#v\n", nc.GlobalFloat64("global-hay"))
		//fmt.Printf("%#v\n", nc.GlobalGeneric("global-bloop"))
		//fmt.Printf("%#v\n", nc.GlobalInt("global-bips"))
		//fmt.Printf("%#v\n", nc.GlobalIntSlice("global-blups"))
		//fmt.Printf("%#v\n", nc.GlobalString("global-snurt"))
		//fmt.Printf("%#v\n", nc.GlobalStringSlice("global-snurkles"))
		//
		//fmt.Printf("%#v\n", nc.FlagNames())
		//fmt.Printf("%#v\n", nc.GlobalFlagNames())
		//fmt.Printf("%#v\n", nc.GlobalIsSet("wat"))
		//fmt.Printf("%#v\n", nc.GlobalSet("wat", "nope"))
		//fmt.Printf("%#v\n", nc.NArg())
		//fmt.Printf("%#v\n", nc.NumFlags())
		//fmt.Printf("%#v\n", nc.Parent())
		//
		//nc.Set("wat", "also-nope")

		//ec := cli.NewExitError("ohwell", 86)
		//fmt.Fprintf(c.App.Writer, "%d", ec.ExitCode())
		//fmt.Printf("made it!\n")
		return nil
	}

	if os.Getenv("HEXY") != "" {
		app.Writer = &hexWriter{}
		app.ErrWriter = &hexWriter{}
	}

	app.Metadata = map[string]interface{}{
		"layers":          "many",
		"explicable":      false,
		"whatever-values": 19.99,
	}

	// ignore error so we don't exit non-zero and break gfmrun README example tests
	_ = app.Run(os.Args)
}

func wopAction(c *cli.Context) error {
	fmt.Fprintf(c.App.Writer, "wop action here\n")
	return nil
}
